package cn.dengta.webapp.trade.entity.meta;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;

import cn.dengta.common.model.Status;
import cn.dengta.context.model.WesKit;
import cn.dengta.webapp.trade.entity.meta.MetaConfig.MetaRuleConfig;
import cn.dengta.webapp.trade.model.TradeType;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Getter;
import lombok.Setter;
import me.codeplayer.util.*;

/**
 * 聊天回复收益的规则配置对象
 */
@Getter
@Setter
public class ChatReplyEarnRule implements MetaRuleConfig {

	private Map<WesKit, EarnRule> rules;

	public static final BigDecimal half = BigDecimal.valueOf(0.5);
	public static final BigDecimal doubled = BigDecimal.valueOf(2);

	@Override
	public void validate() {
		Assert.isTrue(X.isValid(rules), "请设置聊天回复配置！");
		for (Map.Entry<WesKit, EarnRule> entry : this.rules.entrySet()) {
			entry.getValue().validate();
		}
	}

	@Override
	public void init(MetaRuleConfig config) {
		ChatReplyEarnRule rule = (ChatReplyEarnRule) config;
		this.rules = rule.rules;
	}

	public static ChatReplyEarnRule init() {
		ChatReplyEarnRule rule = new ChatReplyEarnRule();
		WesKit[] values = WesKit.values();
		rule.rules = new HashMap<>(values.length, 1F);
		for (WesKit kit : values) {
			rule.rules.computeIfAbsent(kit, k -> initEarnRule());
		}
		return rule;
	}

	public static EarnRule initEarnRule() {
		EarnRule rule = new EarnRule();
		rule.replyBackTime = -1;
		rule.replyOpen = 1;
		rule.replyBackOpen = 0;
		rule.entries = new ChatReplyEarnEntry[] { new ChatReplyEarnEntry(30, doubled), new ChatReplyEarnEntry(60, BigDecimal.ONE), new ChatReplyEarnEntry(90, half), new ChatReplyEarnEntry(90, BigDecimal.ZERO) };
		return rule;
	}

	public EarnRule findEarnRule(@Nonnull WesKit wesKit) {
		return X.isValid(this.rules) ? this.rules.get(wesKit) : initEarnRule();
	}

	/**
	 * 聊天回复规则实体
	 */
	@Setter
	@Getter
	public static class ChatReplyEarnEntry {

		protected Integer times;
		protected BigDecimal factor;

		public ChatReplyEarnEntry() {
		}

		public ChatReplyEarnEntry(Integer times, BigDecimal factor) {
			this.times = times;
			this.factor = factor;
		}

		public void validate() {
			Assert.isTrue(times > 0, "回复时间必须大于0！");
			Assert.isTrue(factor.compareTo(BigDecimal.ZERO) >= 0, "回复收益不能小于0！");
		}

	}

	@Getter
	@Setter
	public static class EarnRule {

		/** 没有回复退回时间；-1：不限制 */
		public Integer replyBackTime;
		/** 回复开关 */
		public Integer replyOpen;
		/** 聊天回复配置 */
		public ChatReplyEarnEntry[] entries;
		/** 回复退回开关 */
		public Integer replyBackOpen;

		public void validate() {
			Assert.isTrue(replyBackOpen != null, "请设置未回复是否退回配置！");
			replyOpen = 1;
			final ChatReplyEarnEntry[] entries = this.entries;
			final int size = X.size(entries);
			Assert.isTrue(size == 4, "聊天回复配置不能为空！");
			BigDecimal greetFactor = entries[0].getFactor();
			Assert.isTrue(greetFactor.compareTo(doubled) <= 0, "搭讪收益最高不能超过2倍！");
			for (int i = entries.length - 1; i > 0; ) {
				ChatReplyEarnEntry entry = entries[i--];
				entry.validate();
				ChatReplyEarnEntry nextEntry = entries[i];
				nextEntry.validate();
				Assert.isTrue(entry.times >= nextEntry.times, "回复时间只能递增！");
				Assert.isTrue(entry.factor.compareTo(nextEntry.factor) <= 0, "回复收益只能递减！");
			}
			final boolean replyBack = Status.asResult(replyBackOpen);
			replyBackTime = replyBack ? entries[size - 1].times : -1;
		}

		/** 回退时间 */
		public Integer maxReplyBackMinute() {
			return entries[entries.length - 1].times;
		}

		/**
		 * 搭讪双倍时间
		 */
		public ChatReplyEarnEntry greetDouble() {
			return entries[0];
		}

		/** 收益减半时间 */
		public ChatReplyEarnEntry halfLife() {
			return entries[2];
		}

		public boolean enabled(TradeType tradeType) {
			return Status.asResult(replyOpen) && ArrayUtil.ins(tradeType, TradeType.COIN_FOR_GREET, TradeType.COIN_FOR_MSG);
		}

		/**
		 * 计算
		 *
		 * @param tradeType 交易类型
		 * @param times 间隔毫秒值
		 * @param defaultValue 默认无收益配置
		 */
		@JSONField(serialize = false)
		public ChatReplyEarnEntry calc(TradeType tradeType, long times, boolean defaultValue) {
			final ChatReplyEarnEntry[] entries = this.entries;
			int length = entries.length;
			ChatReplyEarnEntry last = entries[length - 1];
			if (times > last.times * EasyDate.MILLIS_OF_MINUTE) {
				return last;
			}
			for (int i = 0; i < length - 1; i++) {
				if (i == 0 && tradeType != TradeType.COIN_FOR_GREET) {
					continue;
				}
				if (entries[i].times * EasyDate.MILLIS_OF_MINUTE >= times) {
					return entries[i];
				}
			}
			return defaultValue ? entries[length - 1] : null;
		}

		@JSONField(serialize = false)
		public Integer calcTimes(TradeType tradeType, BigDecimal factor) {
			final ChatReplyEarnEntry[] entries = this.entries;
			int length = entries.length;
			if (factor.compareTo(BigDecimal.ZERO) <= 0) {
				return entries[length - 1].times;
			}
			for (int i = 0; i < length - 1; i++) {
				if (i == 0 && tradeType != TradeType.COIN_FOR_GREET) {
					continue;
				}
				if (entries[i].factor.compareTo(factor) == 0) {
					return entries[i].times;
				}
			}
			return null;
		}

	}

}
